#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<thread>
#include<vector>
#include<mutex>
using namespace std;

//void Print(int n, int i)
//{
//    for (; i < n; i++)
//    {
//        cout << this_thread::get_id() << ":" << i << endl;
//    }
//    cout << endl;
//}

// 多核
//int main()
//{
//    thread t1(Print, 10, 0);
//    thread t2(Print, 20, 10);
//
//    // 获取线程id
//    cout << t1.get_id() << endl;
//    cout << t2.get_id() << endl;
//
//    //...
//    t1.join();
//    t2.join();
//
//    return 0;
//}

//int main()
//{
//    std::cout << "countdown:\n";
//    for (int i = 10; i > 0; --i) {
//        std::cout << i << std::endl;
//        std::this_thread::sleep_for(std::chrono::seconds(2));
//    }
//    std::cout << "Lift off!\n";
//    return 0;
//}

#include <iostream> // std::cout
#include <iomanip> // std::put_time
#include <thread> // std::this_thread::sleep_until
#include <chrono> // std::chrono::system_clock
#include <ctime> // std::time_t, std::tm, std::localtime, std::mktime

//int main()
//{
//    using std::chrono::system_clock;
//    std::time_t tt = system_clock::to_time_t(system_clock::now());
//    struct std::tm* ptm = std::localtime(&tt);
//
//    std::cout << "Current time: " << std::put_time(ptm, "%X") << '\n';
//    std::cout << "Waiting for the next minute to begin...\n";
//
//    ++ptm->tm_min; ptm->tm_sec = 0;
//    std::this_thread::sleep_until(system_clock::from_time_t(mktime(ptm)));
//    std::cout << std::put_time(ptm, "%X") << " reached!\n";
//    return 0;
//}

//int main()
//{
//    using namespace std::chrono;
//    duration<int, std::ratio<60 * 60 * 24> > one_day(1);
//    system_clock::time_point today = system_clock::now();
//    system_clock::time_point tomorrow = today + one_day;
//    time_t tt;
//    tt = system_clock::to_time_t(today);
//    std::cout << "today is: " << ctime(&tt);
//    tt = system_clock::to_time_t(tomorrow);
//    std::cout << "tomorrow will be: " << ctime(&tt);
//
//    return 0;
//}

///////////////////////////////////////////////////////////////

//int x = 0;
//mutex mtx;
//
//void Print(int n)
//{
//    mtx.lock();
//    for (int i = 0; i < n; i++)
//    {
//        // t1 t2
//        ++x;
//    }
//    mtx.unlock();
//
//}
//
//class A
//{
//public:
//    void func()
//    {}
//};
//
//int main()
//{
//    thread t1(Print, 10000000);
//    thread t2(Print, 20000000);
//    t1.join();
//    t2.join();
//
//    cout << x << endl;
//
//    return 0;
//}

//void Print(int n, int& rx, mutex& rmtx)
//{
//    rmtx.lock();
//    for (int i = 0; i < n; i++)
//    {
//        // t1 t2
//        ++rx;
//    }
//    rmtx.unlock();
//}
//
//int main()
//{
//    int x = 0;
//    mutex mtx;
//    // 这里必须要用ref()传参，现成中拿到的才是x和mtx的引用，具体原因需要看下面thread源码中的分析
//    // https://legacy.cplusplus.com/reference/functional/ref/?kw=ref
//    thread t1(Print, 1000000, ref(x), ref(mtx));
//    thread t2(Print, 2000000, ref(x), ref(mtx));
//
//    t1.join();
//    t2.join();
//    cout << x << endl;
//
//    return 0;
//}

//void* _Invoker_proc(void* ptr)
//{
//    _Tuple* tptr = (_Tuple*)ptr;
//
//    Print(tptr[1], tptr[2], tptr[3])
//}

//int main()
//{
//    int x = 0;
//    mutex mtx;
//
//    // 将上面的代码改成使用lambda捕获外层的对象，也就可以不用传参数，间接解决了上面的问题
//    auto Print = [&x, &mtx](size_t n) {
//        mtx.lock();
//        for (size_t i = 0; i < n; i++)
//        {
//            ++x;
//        }
//        mtx.unlock();
//    };
//
//    thread t1(Print, 1000000);
//    thread t2(Print, 2000000);
//
//    t1.join();
//    t2.join();
//    cout << x << endl;
//    return 0;
//}

std::timed_mutex mtx;
void fireworks(int i)
{
	//std::cout << i;
	// waiting to get a lock: each thread prints "-" every 200ms:
	while (!mtx.try_lock_for(std::chrono::milliseconds(1000)))
	{
		std::cout << "-";
	}
	std::cout << i;

	// got a lock! - wait for 1s, then this thread prints "*"
	std::this_thread::sleep_for(std::chrono::milliseconds(5000));
	std::cout << "*\n";

	mtx.unlock();
}

//int main()
//{
//	//std::thread threads[2];
//	vector<std::thread> threads(2);
//
//
//	// 利用移动赋值的方式，将创建的临时对象(右值对象)移动赋值给创建好的空线程对象
//	for (int i = 0; i < 2; ++i)
//		threads[i] = std::thread(fireworks, i);
//
//	for (auto& th : threads)
//		th.join();
//
//	return 0;
//}

//int main()
//{
//	int x = 0;
//	mutex mtx;
//	auto Print = [&x, &mtx](size_t n) {
//		{
//			lock_guard<mutex> lock(mtx);
//			//LockGuard<mutex> lock(mtx);
//			//mtx.lock();
//			for (size_t i = 0; i < n; i++)
//			{
//				++x;
//			}
//			//mtx.unlock();
//		}
//
//		for (size_t i = 0; i < 10; i++)
//		{
//			cout << x << endl;
//		}
//	};
//
//	thread t1(Print, 1000000);
//	thread t2(Print, 2000000);
//	t1.join();
//	t2.join();
//	cout << x << endl;
//
//	return 0;
//}

// std::lock example
#include <iostream>       // std::cout
#include <thread>         // std::thread
#include <mutex>          // std::mutex, std::lock

//std::mutex foo, bar;
//
//void task_a() {
//	std::this_thread::sleep_for(std::chrono::seconds(1));
//
//	//foo.lock();
//	//bar.lock(); // replaced by:
//
//	std::lock(foo, bar);
//	std::cout << "task a\n";
//	foo.unlock();
//	bar.unlock();
//}
//
//void task_b() {
//	std::this_thread::sleep_for(std::chrono::seconds(1));
//
//	//bar.lock(); 
//	//foo.lock(); // replaced by:
//
//	std::lock(bar, foo);
//	std::cout << "task b\n";
//	bar.unlock();
//	foo.unlock();
//}
//
//int main()
//{
//	std::thread th1(task_a);
//	std::thread th2(task_b);
//
//	th1.join();
//	th2.join();
//
//	return 0;
//}

// std::lock example
//#include <iostream>       // std::cout
//#include <thread>         // std::thread
//#include <mutex>          // std::mutex, std::try_lock
//
//std::mutex foo, bar;
//
//void task_a() {
//	foo.lock();
//	bar.lock();
//	std::cout << "task a\n";
//	// ...
//	foo.unlock();
//	bar.unlock();
//}
//
//void task_b() {
//	int x = try_lock(bar, foo);
//	if (x == -1) {
//		std::cout << "task b\n";
//		// ...
//		bar.unlock();
//		foo.unlock();
//	}
//	else {
//		std::cout << "[task b failed: mutex " << (x ? "foo" : "bar") << " locked]\n";
//	}
//}
//
//int main()
//{
//	std::thread th1(task_a);
//	std::thread th2(task_b);
//
//	th1.join();
//	th2.join();
//
//	return 0;
//}

// call_once example
#include <iostream>       // std::cout
#include <thread>         // std::thread, std::this_thread::sleep_for
#include <chrono>         // std::chrono::milliseconds
#include <mutex>          // std::call_once, std::once_flag

int winner;
void set_winner(int x) { winner = x; }
std::once_flag winner_flag;

void wait_1000ms(int id) {
	// count to 1000, waiting 1ms between increments:
	for (int i = 0; i < 100; ++i)
		std::this_thread::sleep_for(std::chrono::milliseconds(1));
	// claim to be the winner (only the first such call is executed):
	std::call_once(winner_flag, set_winner, id);
}

int main()
{
	std::thread threads[10];
	// spawn 10 threads:
	for (int i = 0; i < 10; ++i)
		threads[i] = std::thread(wait_1000ms, i + 1);

	std::cout << "waiting for the first among 10 threads to count 1000 ms...\n";

	for (auto& th : threads) th.join();
	std::cout << "winner thread: " << winner << '\n';

	return 0;
}